package com.scorpio.order.service.impl;

import java.util.List;

import com.scorpio.common.exception.CustomException;
import com.scorpio.common.utils.DateUtils;
import com.scorpio.common.utils.MathUtil;
import com.scorpio.common.utils.StringUtils;
import com.scorpio.goods.service.IGoodsSpecService;
import com.scorpio.order.domain.OrderGoodsEntity;
import com.scorpio.order.enums.LogisticsTypeEmun;
import com.scorpio.order.enums.OrderStatusEmun;
import com.scorpio.order.service.IOrderGoodsService;
import com.scorpio.order.service.IOrderSnsServer;
import com.scorpio.order.vo.UpdateOrderMoneyVo;
import com.scorpio.order.vo.UpdateSendOutVo;
import com.scorpio.redis.cachelock.RedisLock;
import com.scorpio.redis.cachelock.RedisLockException;
import com.scorpio.sdk.service.SFService;
import com.scorpio.sdk.service.WXPayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.scorpio.order.mapper.OrderMapper;
import com.scorpio.order.domain.OrderEntity;
import com.scorpio.order.service.IOrderService;
import com.scorpio.common.service.impl.BaseServiceImpl;
import org.springframework.transaction.annotation.Transactional;

/**
 * 订单Service业务层处理
 *
 * @author scorpio
 * @date 2021-11-29
 */
@Service
public class OrderServiceImpl extends BaseServiceImpl<OrderMapper, OrderEntity> implements IOrderService {

    @Autowired
    private RedisLock redisLock;

    @Autowired
    private SFService sfService;

    @Autowired
    private IOrderGoodsService orderGoodsService;

    @Autowired
    private IGoodsSpecService goodsSpecService;

    //查询
    @Override
    public OrderEntity selectById(Long id) {
        return baseDao.selectById(id);
    }

    //查询列表
    @Override
    public List<OrderEntity> selectList(OrderEntity entity) {
        List<OrderEntity> list = baseDao.list(entity);
        for (OrderEntity orderEntity : list) {
            orderEntity.setOrderGoods(orderGoodsService.selectByOrder(orderEntity.getId()));
        }
        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateLogisticsInfo(UpdateSendOutVo vo) {
        if (!sfService.validateWaybillno(vo.getLogisticsNumber())) {
            throw new CustomException("该订单号不正确哦");
        }
        OrderEntity entity = baseDao.selectById(vo.getId());
        String lockKey = "update_order_status:" + entity.getOrderSn();
        if (redisLock.lock(lockKey, 5)) {
            try {
                entity = baseDao.selectById(vo.getId());
                if (entity == null) {
                    throw new CustomException("不存在或已删除");
                } else if (!OrderStatusEmun.Status3.getValue().equals(entity.getStatus())) {
                    throw new CustomException("订单状态不正确，请刷新");
                }
                return baseDao.updateLogisticsInfo(vo.getId(), vo.getLogisticsNumber(), vo.getLogisticsType());
            } finally {
                redisLock.unlock(lockKey);
            }
        }
        throw new RedisLockException();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateSendOut(UpdateSendOutVo vo) {
        OrderEntity entity = baseDao.selectById(vo.getId());
        String lockKey = "update_order_status:" + entity.getOrderSn();
        if (redisLock.lock(lockKey, 5)) {
            try {
                entity = baseDao.selectById(vo.getId());
                if (entity == null) {
                    throw new CustomException("无效订单");
                }
                if (!OrderStatusEmun.Status2.getValue().equals(entity.getStatus())) {
                    throw new CustomException("请刷新订单状态");
                }
                if (LogisticsTypeEmun.ZT.getValue().equals(vo.getLogisticsType())) {
                    return baseDao.updateSendZtOut(vo.getId(), LogisticsTypeEmun.ZT.getValue());
                } else {
                    if (StringUtils.isEmpty(vo.getLogisticsNumber())) {
                        throw new CustomException("缺少物流单号");
                    }
                    if (LogisticsTypeEmun.SF.getValue().equals(vo.getLogisticsType())) {
                        if (!sfService.validateWaybillno(vo.getLogisticsNumber())) {
                            throw new CustomException("该订单号不正确哦");
                        }
                    } else {
                        throw new CustomException("暂不支持的物流");
                    }
                    return baseDao.updateSendOut(vo.getId(), vo.getLogisticsNumber(), vo.getLogisticsType());
                }
            } finally {
                redisLock.unlock(lockKey);
            }
        }
        throw new RedisLockException();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int scanOverdueb() {
        int count = 0;
        List<OrderEntity> list = baseDao.scanOverdueb();
        for (OrderEntity entity : list) {
            if (!OrderStatusEmun.Status0.getValue().equals(entity.getStatus())) {
                throw new CustomException("订单状态不正确");
            }
            if (baseDao.updateStatus(entity.getId(), OrderStatusEmun.Status1.getValue()) == 0) {
                throw new CustomException("操作失败");
            }
            List<OrderGoodsEntity> orderGoods = orderGoodsService.selectByOrder(entity.getId());
            for (OrderGoodsEntity orderGood : orderGoods) {
                goodsSpecService.updateReturnInventory(orderGood.getSpecId(), orderGood.getBuyTotal());
            }
        }
        return count;
    }

    @Override
    public List<OrderEntity> timeoutOrders() {
        return baseDao.timeoutOrders();
    }

    @Override
    public List<OrderEntity> selectByStatus(OrderStatusEmun statusEmun) {
        return baseDao.selectByStatus(statusEmun.getValue());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateFinish(OrderEntity orderEntity) {
        String lockKey = "update_order_status:" + orderEntity.getOrderSn();
        if (redisLock.lock(lockKey, 5)) {
            try {
                orderEntity = baseDao.selectById(orderEntity.getId());
                if (!OrderStatusEmun.Status3.getValue().equals(orderEntity.getStatus())) {
                    throw new CustomException("订单状态不正确");
                }
                if (baseDao.updateStatus(orderEntity.getId(), OrderStatusEmun.Status4.getValue()) == 0) {
                    throw new CustomException("操作失败");
                }
                return;
            } finally {
                redisLock.unlock(lockKey);
            }
        }
        throw new RedisLockException();
    }

    @Autowired
    private WXPayService wxPayService;

    @Autowired
    private IOrderSnsServer orderSnsServer;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateOrderMoney(UpdateOrderMoneyVo vo) {
        if (vo.getMoney() < 0.01f) {
            throw new CustomException("无效的修改金额");
        }
        OrderEntity orderEntity = baseDao.selectById(vo.getId());
        if (orderEntity == null) {
            throw new CustomException("不存在的订单");
        }
        String lockKey = "update_order_status:" + orderEntity.getOrderSn();
        if (redisLock.lock(lockKey, 5)) {
            try {
                orderEntity = baseDao.selectById(orderEntity.getId());
                if (!OrderStatusEmun.Status0.getValue().equals(orderEntity.getStatus())) {
                    throw new CustomException("该订单状态无法修改,请刷新后查看");
                }
                int count = baseDao.updateOrderMoney(vo.getId(), vo.getMoney());
                if (count > 0) {
                    String newOrderSn = MathUtil.getRandLetter(MathUtil.NUMERIC, DateUtils.dateTimeNow(), 4);
                    String oldOrderSn = orderEntity.getOrderSn();
                    if (baseDao.updateOrderSn(vo.getId(), newOrderSn) == 0 || orderSnsServer.save(orderEntity.getId(), newOrderSn) == 0) {
                        throw new CustomException("修改订单失败");
                    }
                    wxPayService.payClose(oldOrderSn);
                }
                return count;
            } finally {
                redisLock.unlock(lockKey);
            }
        }
        throw new RedisLockException();
    }

}
